using System;
using System.Collections.Generic;
using System.Linq;
using Urs.Core.Data;
using Urs.Data.Domain.Users;
using Urs.Data.Domain.Orders;
using Urs.Data.Domain.Payments;
using Urs.Data.Domain.Shipping;


namespace Urs.Services.Users
{
    public partial class UserReportService : IUserReportService
    {
        #region Fields

        private readonly IRepository<User> _userRepository;
        private readonly IRepository<Order> _orderRepository;
        private readonly IUserService _userService;
        
        
        #endregion

        #region Ctor
        
        public UserReportService(IRepository<User> userRepository,
            IRepository<Order> orderRepository, IUserService userService
            )
        {
            this._userRepository = userRepository;
            this._orderRepository = orderRepository;
            this._userService = userService;
        }

        #endregion

        #region Methods

        public virtual IList<BestUserReportLine> GetBestUsersReport(DateTime? startTime,
            DateTime? endTime, OrderStatus? os, PaymentStatus? ps, ShippingStatus? ss, int orderBy)
        {
            int? orderStatusId = null;
            if (os.HasValue)
                orderStatusId = (int)os.Value;

            int? paymentStatusId = null;
            if (ps.HasValue)
                paymentStatusId = (int)ps.Value;

            int? shippingStatusId = null;
            if (ss.HasValue)
                shippingStatusId = (int)ss.Value;
            var query1 = from c in _userRepository.Table
                         join o in _orderRepository.Table on c.Id equals o.UserId
                         where (!startTime.HasValue || startTime.Value <= o.CreateTime) &&
                         (!endTime.HasValue || endTime.Value >= o.CreateTime) &&
                         (!orderStatusId.HasValue || orderStatusId == o.OrderStatusId) &&
                         (!paymentStatusId.HasValue || paymentStatusId == o.PaymentStatusId) &&
                         (!shippingStatusId.HasValue || shippingStatusId == o.ShippingStatusId) &&
                         (!o.Deleted) &&
                         (!c.Deleted)
                         select new { c, o };

            var query2 = from co in query1
                         group co by co.c.Id into g
                         select new
                         {
                             UserId = g.Key,
                             OrderTotal = g.Sum(x => x.o.OrderTotal),
                             OrderCount = g.Count()
                         };
            switch (orderBy)
            {
                case 1:
                    {
                        query2 = query2.OrderByDescending(x => x.OrderTotal);
                    }
                    break;
                case 2:
                    {
                        query2 = query2.OrderByDescending(x => x.OrderCount);
                    }
                    break;
                default:
                    throw new ArgumentException("Wrong orderBy parameter", "orderBy");
            }

            query2 = query2.Take(20);

            var result = query2.ToList().Select(x =>
            {
                return new BestUserReportLine()
                {
                    UserId = x.UserId,
                    OrderTotal = x.OrderTotal,
                    OrderCount = x.OrderCount
                };
            }).ToList();
            return result;
        }

        public virtual int GetRegisteredUsersReport(int days)
        {
            DateTime date = DateTime.Now.AddDays(-days);

            var registeredUserRole = _userService.GetUserRoleBySystemName(SystemRoleNames.Registered);
            if (registeredUserRole == null)
                return 0;

            var query = from c in _userRepository.Table
                        from cr in c.UserRoles
                        where !c.Deleted &&
                        cr.Id == registeredUserRole.Id &&
                        c.CreateTime >= date 
                        select c;
            int count = query.Count();
            return count;
        }

        #endregion
    }
}